#region Imports

using System;
using System.Collections.Generic;
using System.Data;

using CodeSmith.Engine;
using SchemaExplorer;

#endregion

public class LinqFunctions : CodeTemplate
{	
	#region Naming
	
	public string PropertyName(ColumnSchema column)
	{	
		string propertyName = PascalCase(column.Name);
		if (propertyName == EntityName(column.Table)) // .NET does not allow class to have property of same name
			propertyName += "1"; // Append 1 as this is what LinqToSql does
		return propertyName;
	}
	
	public string ParameterName(ColumnSchema column)
	{
		string parameterName = PascalCase(column.Name);
		return Char.ToLower(parameterName[0]) + parameterName.Substring(1);
	}
	
	public string TableName(TableSchema table)
	{
		return (table.Name.EndsWith("s")) ? PascalCase(table.Name) : PascalCase(table.Name) + "s";
	}

	public string EntityName(TableSchema table)
	{
		if (table.Name.EndsWith("ies"))
			return PascalCase(table.Name.Substring(0, table.Name.Length-3)) + "y";
			
		if (table.Name.EndsWith("s")) 
			return PascalCase(table.Name.Substring(0, table.Name.Length-1));
			
		return PascalCase(table.Name);
	}	
	
	public string DatabaseName(DatabaseSchema database)
	{
		return PascalCase(database.Name);
	}
	
	private string PascalCase(string text)
	{
		string newText = "";
		bool nextUpper = true;
		for (int i = 0; i < text.Length; i++)
			switch(text[i]) {
				case '_':
				case '-':
				case ' ': {
					nextUpper = true;
					break;
				}
				default: {
					if (nextUpper)
						newText += char.ToUpper(text[i]);
					else
						newText += text[i];
					nextUpper = false;		
					break;
				}
			}
		return newText;
	}
	
	public string CurrentUserName()
	{
		string userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name.ToString();
		return (userName.IndexOf("\\") > 0) ? userName.Remove(0, userName.IndexOf("\\") + 1) : userName;
	}

	#endregion
	
	#region Attribute generation
		
	public string AttributeColumnDbType(ColumnSchema column)
	{
		string columnDbType = column.NativeType.ToString();
		if (column.NativeType.Contains("char"))
			columnDbType += String.Format("({0})", column.Size);
		if (!column.AllowDBNull)
			columnDbType += " NOT NULL";
		if ((bool)column.ExtendedProperties["CS_IsIdentity"].Value)
			columnDbType += " IDENTITY";
		return columnDbType;
	}
	
	public string AttributeColumnList(MemberColumnSchemaCollection columns)
	{
		List<string> list = new List<string>();
		foreach(ColumnSchema column in columns)
			list.Add(column.Name);
		return String.Join(", ", list.ToArray());
	}
	
	#endregion
	
	#region .NET mapping
	
	public string MethodParametersDefinition(ColumnSchemaCollection columns)
	{
		List<String> parameters = new List<String>();
		foreach(ColumnSchema column in columns)
			parameters.Add(SystemType(column) + " " + ParameterName(column));
		return String.Join(", ", parameters.ToArray());
	}

	public string MethodArguments(ColumnSchemaCollection columns)
	{
		List<String> parameters = new List<String>();
		foreach(ColumnSchema column in columns)
			if ((column.AllowDBNull) && (column.SystemType.ToString() != "System.String"))
				parameters.Add(PropertyName(column) + ".Value");
			else
				parameters.Add(PropertyName(column));
		return String.Join(", ", parameters.ToArray());
	}
	
	public string NullableSystemType(ColumnSchema column)
	{
		string systemType = SystemType(column);		
		if ((!column.AllowDBNull) || (systemType == "System.String") || (systemType == "Object")
			|| systemType == "System.Data.Linq.Binary" || systemType == "System.Linq.Xml")
			return systemType;
		else
			return "System.Nullable<" + systemType + ">";
	}
	
	public string SystemType(ColumnSchema column)
	{
		string type = "";
		switch(column.DataType)
		{
			case DbType.Binary: 
				type = "System.Data.Linq.Binary";
				break;
			case DbType.Xml:
				type = "System.Linq.Xml";
				break;
			default:
				type = column.SystemType.ToString();
				break;
		}
		return type.Replace("System.", "System.");
	}
	
	#endregion
}